package com.pai4j.user.service.relation;

import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.enums.AccountRelationTypeEnum;
import com.pai4j.common.enums.InteractionMessageTypeEnum;
import com.pai4j.common.enums.RedisKeyEnum;
import com.pai4j.common.enums.messagequeue.MessageQueueEnum;
import com.pai4j.common.service.messagequeue.producer.MessageQueueProducer;
import com.pai4j.common.util.DateUtils;
import com.pai4j.common.util.RedisUtil;
import com.pai4j.domain.vo.request.mess.MessageNotifyVO;
import com.pai4j.user.repository.dao.IFriendDAO;
import com.pai4j.user.repository.entity.FriendEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Date;

/**
 * 用户-用户 关注/取关（仅friend表）
 * 
 * 注意：本服务使用 pai4j_friend 表和独立的 FRIEND_FOLLOW_LIST_CACHE 缓存
 * 与 AbstractAccountRelationService（使用 pai4j_account_relation 表和 ACCOUNT_RELATION_LIST_CACHE）完全隔离
 */
@Slf4j
@Service
public class FriendFollowService {

    @Autowired
    private IFriendDAO friendDAO;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MessageQueueProducer<Object, Long> messageQueueProducer;

    private static final int STATUS_FOLLOWING = 1;
    private static final int STATUS_UNFOLLOW = 0;
    
    /**
     * 关注/取关
     *
     * @param sourceAccount: 发起关注的用户
     * @param targetAccount： 被关注用户
     * @return
     */

    public Boolean follow(String sourceAccount, String targetAccount) {
        Assert.hasText(sourceAccount, "sourceAccount empty");
        Assert.hasText(targetAccount, "targetAccount empty");
        Assert.isTrue(!sourceAccount.equals(targetAccount), "cannot follow self");
        upsertFriend(sourceAccount, targetAccount, STATUS_FOLLOWING);
        // 缓存：把target加入source的关注列表（使用 FRIEND_FOLLOW_LIST_CACHE）
        addFollowingCache(sourceAccount, targetAccount);
        // 计数缓存失效（使用 FRIEND_FOLLOW_LIST_CACHE）
        invalidateCounts(sourceAccount, targetAccount);
        // 发送互动消息（粉丝关注）
        sendFollowInteraction(sourceAccount, targetAccount);
        return true;
    }

    public Boolean unfollow(String sourceAccount, String targetAccount) {
        Assert.hasText(sourceAccount, "sourceAccount empty");
        Assert.hasText(targetAccount, "targetAccount empty");
        upsertFriend(sourceAccount, targetAccount, STATUS_UNFOLLOW);
        // 缓存：从source关注列表移除target（使用 FRIEND_FOLLOW_LIST_CACHE）
        removeFollowingCache(sourceAccount, targetAccount);
        // 计数缓存失效（使用 FRIEND_FOLLOW_LIST_CACHE）
        invalidateCounts(sourceAccount, targetAccount);
        return true;
    }

    /**
     * 判断是否正在关注（使用 friend 表独立缓存）
     * 
     * @param sourceAccount 发起关注的用户
     * @param targetAccount 被关注的用户
     * @return true=正在关注，false=未关注
     */
    public boolean isFollowing(String sourceAccount, String targetAccount) {
        String key = friendFollowingListKey(sourceAccount);
        if (redisUtil.exists(key)) {
            return redisUtil.zIsExist(key, targetAccount);
        }
        // 回退DB（查询 pai4j_friend 表）
        FriendEntity entity = friendDAO.findAllByUserIdAndFriendId(sourceAccount, targetAccount);
        return entity != null && Integer.valueOf(STATUS_FOLLOWING).equals(entity.getStatus());
    }

    private void upsertFriend(String userId, String friendId, int status) {
        FriendEntity fe = friendDAO.findAllByUserIdAndFriendId(userId, friendId);
        Date now = new Date();
        if (fe == null) {
            fe = new FriendEntity();
            fe.setUserId(userId);
            fe.setFriendId(friendId);
            fe.setApplyDate(now);
        }
        fe.setStatus(status);
        fe.setHandleDate(now);
        friendDAO.save(fe);
    }

    /**
     * 添加关注缓存（使用 FRIEND_FOLLOW_LIST_CACHE）
     */
    private void addFollowingCache(String sourceAccount, String targetAccount) {
        String key = friendFollowingListKey(sourceAccount);
        redisUtil.zadd(key, targetAccount, DateUtils.getCurrentTimeMillis(),
                RedisKeyEnum.FRIEND_FOLLOW_LIST_CACHE.getExpireTime());
    }

    /**
     * 移除关注缓存（使用 FRIEND_FOLLOW_LIST_CACHE）
     */
    private void removeFollowingCache(String sourceAccount, String targetAccount) {
        String key = friendFollowingListKey(sourceAccount);
        redisUtil.zremove(key, targetAccount);
    }

    /**
     * 清除计数缓存（使用 FRIEND_FOLLOW_LIST_CACHE）
     */
    private void invalidateCounts(String sourceAccount, String targetAccount) {
        String followingKey = friendFollowingCountKey(sourceAccount);
        String followersKey = friendFollowersCountKey(targetAccount);
        redisUtil.remove(followingKey);
        redisUtil.remove(followersKey);
    }

    /**
     * 获取关注列表缓存key（使用 FRIEND_FOLLOW_LIST_CACHE）
     * 格式：WEB_PAI4J_FRIEND_FOLLOW_LIST_CACHE_FOLLOWING_LIST_AC_{account}
     */
    private String friendFollowingListKey(String account) {
        return RedisKeyEnum.FRIEND_FOLLOW_LIST_CACHE.getKey(
                "FOLLOWING_LIST", "AC", account);
    }

    /**
     * 获取粉丝数缓存key（使用 FRIEND_FOLLOW_LIST_CACHE）
     * 格式：WEB_PAI4J_FRIEND_FOLLOW_LIST_CACHE_FOLLOWERS_COUNT_AC_{account}
     */
    private String friendFollowersCountKey(String account) {
        return RedisKeyEnum.FRIEND_FOLLOW_LIST_CACHE.getKey(
                "FOLLOWERS_COUNT", "AC", account);
    }

    /**
     * 获取关注数缓存key（使用 FRIEND_FOLLOW_LIST_CACHE）
     * 格式：WEB_PAI4J_FRIEND_FOLLOW_LIST_CACHE_FOLLOWING_COUNT_AC_{account}
     */
    private String friendFollowingCountKey(String account) {
        return RedisKeyEnum.FRIEND_FOLLOW_LIST_CACHE.getKey(
                "FOLLOWING_COUNT", "AC", account);
    }

    private void sendFollowInteraction(String follower, String followee) {
        try {
            MessageNotifyVO notify = new MessageNotifyVO();
            notify.setSenderId(follower);
            notify.setReceiverId(followee);
            notify.setMessage("关注了你");
            // 互动消息类型在消费者中设置为INTERACTION大类，这里透传扩展字段
            // messageType=关注
            notify.setMessageType(InteractionMessageTypeEnum.FOLLOW.getCode());
            // 通过互动消息持久化队列
            messageQueueProducer.send(MessageQueueEnum.QUEUE_PERSISTENT_INTERACTION_MESSAGE, notify);
            log.info("sent follow interaction message. follower={}, followee={}", follower, followee);
        } catch (Exception e) {
            log.error("send follow interaction error. follower={}, followee={}", follower, followee, e);
        }
    }

    /**
     * 获取用户的粉丝数量（从friend表查询，带缓存）
     * 粉丝是指关注该用户的其他用户数量（该用户作为friend_id，status=1的记录数量）
     * 使用 FRIEND_FOLLOW_LIST_CACHE 独立缓存
     *
     * @param account 用户账号
     * @return 粉丝数量
     */
    public Long getFollowersCount(String account) {
        Assert.hasText(account, "account empty");
        String countCacheKey = friendFollowersCountKey(account);

        // 先从缓存获取
        if (redisUtil.exists(countCacheKey)) {
            String countStr = redisUtil.get(countCacheKey);
            if (countStr != null && !WebConstant.CACHE_NONE.equals(countStr)) {
                try {
                    return Long.valueOf(countStr);
                } catch (NumberFormatException e) {
                    log.warn("parse followers count from cache error, key={}, value={}", countCacheKey, countStr, e);
                    redisUtil.remove(countCacheKey);
                }
            }
        }

        // 缓存不存在或失效，查询数据库（friend表：friend_id=account且status=1）
        Long followersCount;
        try {
            followersCount = friendDAO.countByFriendIdAndStatus(account, STATUS_FOLLOWING);
        } catch (Exception e) {
            log.error("count followers from friend table error, account={}", account, e);
            followersCount = 0L;
        }

        // 更新缓存，设置5分钟过期时间
        redisUtil.set(countCacheKey, String.valueOf(followersCount), 5 * 60);

        return followersCount;
    }

    /**
     * 获取用户的关注数量（从friend表查询，带缓存）
     * 关注是指该用户关注的其他用户数量（该用户作为user_id，status=1的记录数量）
     * 使用 FRIEND_FOLLOW_LIST_CACHE 独立缓存
     *
     * @param account 用户账号
     * @return 关注数量
     */
    public Long getFollowingCount(String account) {
        Assert.hasText(account, "account empty");
        String countCacheKey = friendFollowingCountKey(account);

        // 先从缓存获取
        if (redisUtil.exists(countCacheKey)) {
            String countStr = redisUtil.get(countCacheKey);
            if (countStr != null && !WebConstant.CACHE_NONE.equals(countStr)) {
                try {
                    return Long.valueOf(countStr);
                } catch (NumberFormatException e) {
                    log.warn("parse following count from cache error, key={}, value={}", countCacheKey, countStr, e);
                    redisUtil.remove(countCacheKey);
                }
            }
        }

        // 缓存不存在或失效，查询数据库（friend表：user_id=account且status=1）
        Long followingCount;
        try {
            followingCount = friendDAO.countByUserIdAndStatus(account, STATUS_FOLLOWING);
        } catch (Exception e) {
            log.error("count following from friend table error, account={}", account, e);
            followingCount = 0L;
        }

        // 更新缓存，设置5分钟过期时间
        redisUtil.set(countCacheKey, String.valueOf(followingCount), 5 * 60);

        return followingCount;
    }
}
